﻿using System;
using System.Xml;
using SolidQBCPLibrary;
using System.Collections.Generic;

namespace SolidQ.BCP
{
    class XmlDriver
    {
        private bool _showDetailedInfo;
        public bool _writeErrorsOnEventLog;
        private bool _continueOnError;
        public int NotifyAfter;
        public int BatchSize;
        public string HintStrings;
        public bool AutomaticCollationResolution;

        private string _encryptionkey;

        public BCPCredentials source;
        public BCPCredentials destination;

        public List<BCPDataFlow> dataFlows = new List<BCPDataFlow>();



        public XmlDriver()
        {
            source = null;
            destination = null;

            NotifyAfter = 10000;
            BatchSize = 4096;
            HintStrings = "";

        }

        public void LoadFromXmlFile(string pathToFile)
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(pathToFile);

            XmlElement xmlRootNode = (XmlElement)xmlDoc.SelectSingleNode("/SolidQBCP");
            if (xmlRootNode == null)
            {
                throw new XmlException("The root element must be SolidQBCP");
            }
            XmlAttribute attr = null;

            attr = xmlRootNode.Attributes["ContinueOnError"];
            if (attr == null)
            {
                this._continueOnError = true;
            }
            else
            {
                this._continueOnError = bool.Parse(attr.Value);
            }

            attr = xmlRootNode.Attributes["WriteErrorsOnEventLog"];
            if (attr == null)
            {
                this._writeErrorsOnEventLog = false;
            }
            else
            {
                this._writeErrorsOnEventLog = bool.Parse(attr.Value);
            }

            attr = xmlRootNode.Attributes["ShowDetailedInfo"];
            if (attr == null)
            {
                this._showDetailedInfo = false;
            }
            else
            {
                this._showDetailedInfo = bool.Parse(attr.Value);
            }

            attr = xmlRootNode.Attributes["BatchSize"];
            if (attr != null)
            {
                this.BatchSize = Int32.Parse(attr.Value);
            }

            attr = xmlRootNode.Attributes["NotifyAfter"];
            if (attr != null)
            {
                this.NotifyAfter = Int32.Parse(attr.Value);
            }

            attr = xmlRootNode.Attributes["AutomaticCollationResolution"];
            if (attr != null)
            {
                this.AutomaticCollationResolution = Boolean.Parse(attr.Value);
            }

            attr = xmlRootNode.Attributes["Hints"];
            if (attr != null)
            {
                this.HintStrings = attr.Value;
            }

            XmlElement key = (XmlElement)xmlDoc.SelectSingleNode("/SolidQBCP/credentials/key");
            _encryptionkey = GetEncryptionKey(key);

            XmlElement xmlCredentialsNode = (XmlElement)xmlDoc.SelectSingleNode("/SolidQBCP/credentials");

            CreateBCPCredentialsFromXmlElement(xmlCredentialsNode);



            XmlNodeList dfs = (XmlNodeList)xmlDoc.SelectNodes("/SolidQBCP/dataflow");
            foreach (XmlElement df in dfs)
            {
                dataFlows.Add(CreateDataFlowFromXmlElement(df));
            }


        }

        private string GetEncryptionKey(XmlElement xmlDoc)
        {
            XmlCDataSection key = (XmlCDataSection)xmlDoc.ChildNodes[0];
            if (key == null)
                throw new XmlException("CDATA with key encription is missing");

            return (key.Value);
        }


        private BCPCredentials _createBCPCredentialFromXmlElement(XmlElement attributesSource)
        {
            BCPCredentials source = new BCPCredentials();

            bool isPasswordEncrypted = false;
            XmlAttribute attr = null;

            attr = attributesSource.Attributes["SqlInstance"];
            if (attr == null)
            {
                throw new XmlException("Type attribute is missing");
            }
            source.InstanceName = attr.Value;

            attr = attributesSource.Attributes["DatabaseName"];
            if (attr == null)
            {
                throw new XmlException("DatabaseName attribute is missing");
            }
            source.DatabaseName = attr.Value;

            attr = attributesSource.Attributes["IntegratedSecurity"];
            if (attr == null)
            {
                source.UseIntegratedSecurity = false;
            }
            else
            {
                source.UseIntegratedSecurity = bool.Parse(attr.Value);
            }


            attr = attributesSource.Attributes["User"];
            if (attr == null)
            {
                throw new XmlException("User attribute is missing");
            }
            source.UserName = attr.Value;


            attr = attributesSource.Attributes["IsPasswordEncrypted"];
            if (attr == null)
            {
                throw new XmlException("IsPasswordEncrypted attribute is missing");
            }
            else
            {
                isPasswordEncrypted = bool.Parse(attr.Value);
            }

            attr = attributesSource.Attributes["Password"];
            if (attr == null)
            {
                throw new XmlException("Password attribute is missing");
            }
           
            source.Password = attr.Value;
            

            return (source);
        }

        private void CreateBCPCredentialsFromXmlElement(XmlElement xmlFileAction)
        {
            source = new BCPCredentials();
            destination = new BCPCredentials();

            XmlElement xNodeSource = (XmlElement)xmlFileAction["source"];
            XmlElement xNodeDestination = (XmlElement)xmlFileAction["destination"];

            //XmlAttributeCollection attributesSource = xNodeSource.Attributes;
            //XmlAttributeCollection attributesDestination = xNodeSource.Attributes;


            source = _createBCPCredentialFromXmlElement(xNodeSource);
            destination = _createBCPCredentialFromXmlElement(xNodeDestination);


        }


        private SolidQBCPLibrary.BCPDataFlow CreateDataFlowFromXmlElement(XmlElement xmlFileAction)
        {

            XmlAttribute attr = null;
            XmlElement src = null;
            BCPDataFlow retorno = new BCPDataFlow(source, destination);

            //////////////////////////////////////////////////////////////////////////////////////////
            /// DYNAMIC FILTER DEFINITION
            /// 
            attr = xmlFileAction.Attributes["use_dynamic_filter"];
            if (attr != null)
                retorno.UseDynamicFilter = Boolean.Parse(attr.Value);

            if (retorno.UseDynamicFilter)
            {
                src = (XmlElement)xmlFileAction["dynamic_filter_definition"];
                retorno.DynamicFilterDefinition = src.InnerText;

                attr = src.Attributes["data_type"];
                if (attr != null)
                {
                    retorno.DynamicFilterDataType = attr.Value;
                }

            }

            attr = xmlFileAction.Attributes["id_priority"];
            if (attr != null)
                retorno.IdPriority = Int32.Parse(attr.Value);



            //////////////////////////////////////////////////////////////////////////////////////////
            ///// SOURCE
            /////
            src = (XmlElement)xmlFileAction["source"];
            XmlAttributeCollection attributes = src.Attributes;


            attr = xmlFileAction.Attributes["force_column_mapping"];
            if (attr != null)
                retorno.ForceColumnMapping = Boolean.Parse(attr.Value);

            attr = attributes["TableName"];
            if (attr == null)
            {
                throw new XmlException("TableName attribute is missing");
            }
            retorno.source.TableName = attr.Value;

            attr = attributes["UseQueryAsSource"];
            if (attr != null)
                retorno.source.UseQueryAsSource = Boolean.Parse(attr.Value);
            else
                retorno.source.UseQueryAsSource = false;

            if (retorno.source.UseQueryAsSource)
            {
                attr = attributes["Query"];
                if (attr == null)
                {
                    throw new XmlException("Query attribute is missing");
                }
                retorno.source.Query = attr.Value;
            }

            attr = attributes["ColumnNames"];
            if (attr == null)
            {
                throw new XmlException("ColumnNames attribute is missing");
            }
            retorno.source.SetColumns(attr.Value);

            //////////////////////////////////////////////////////////////////////////////////////////
            /// DESTINATION
            /// 
            XmlElement dst = (XmlElement)xmlFileAction["destination"];
            attributes = dst.Attributes;


            attr = attributes["TableName"];
            if (attr == null)
            {
                throw new XmlException("TableName attribute is missing");
            }
            retorno.destination.TableName = attr.Value;


            attr = attributes["ColumnNames"];
            if (attr == null)
            {
                throw new XmlException("ColumnNames attribute is missing");
            }
            retorno.destination.SetColumns(attr.Value);

            return (retorno);
        }
    }
}
